package handlers

import (
	"fmt"
	"net/http"
	"time"

	alertv1 "github.com/devops-smartbot/devops-smartbot/proto/gen/go/alert/v1"
	commonv1 "github.com/devops-smartbot/devops-smartbot/proto/gen/go/common/v1"
	ticketv1 "github.com/devops-smartbot/devops-smartbot/proto/gen/go/ticket/v1"
	"github.com/devops-smartbot/devops-smartbot/services/api-gateway/internal/clients"
	"github.com/gin-gonic/gin"
)

type AnalyticsHandler struct {
	alertClient  clients.AlertClient
	ticketClient clients.TicketClient
}

func NewAnalyticsHandler(alertClient clients.AlertClient, ticketClient clients.TicketClient) *AnalyticsHandler {
	return &AnalyticsHandler{
		alertClient:  alertClient,
		ticketClient: ticketClient,
	}
}

// GetAnalyticsData handles GET /api/analytics
func (h *AnalyticsHandler) GetAnalyticsData(c *gin.Context) {
	ctx := c.Request.Context()

	// Get alerts for statistics and trend analysis
	alertsResp, err := h.alertClient.ListAlerts(ctx, &alertv1.ListAlertsRequest{
		Pagination: &commonv1.Pagination{
			Page:     1,
			PageSize: 1000,
		},
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get alerts"})
		return
	}

	// Calculate alert statistics
	alertStats := calculateAlertStatistics(alertsResp.Alerts)

	// Get ticket statistics
	ticketStats, err := h.ticketClient.GetTicketStatistics(ctx, &ticketv1.GetTicketStatisticsRequest{})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get ticket statistics"})
		return
	}

	// Get tickets for trend analysis
	ticketsResp, err := h.ticketClient.ListTickets(ctx, &ticketv1.ListTicketsRequest{
		Pagination: &commonv1.Pagination{
			Page:     1,
			PageSize: 1000,
		},
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get tickets"})
		return
	}

	// Calculate trends
	alertTrend := calculateAlertTrend(alertsResp.Alerts)
	ticketTrend := calculateTicketTrend(ticketsResp.Tickets)

	// Calculate metrics
	avgResolutionTime := calculateAvgResolutionTime(ticketsResp.Tickets)
	slaCompliance := calculateSLACompliance(ticketsResp.Tickets)
	mttr := calculateMTTR(alertsResp.Alerts)

	c.JSON(http.StatusOK, gin.H{
		"alerts": gin.H{
			"total": alertStats["total"],
			"byStatus": gin.H{
				"firing":   alertStats["firing"],
				"resolved": alertStats["resolved"],
			},
			"bySeverity": gin.H{
				"critical": alertStats["critical"],
				"warning":  alertStats["warning"],
				"info":     alertStats["info"],
			},
			"trend":     alertTrend,
			"mttr":      mttr,
			"noiseRate": 0.0, // Placeholder
		},
		"tickets": gin.H{
			"total": ticketStats.Total,
			"byStatus": gin.H{
				"open":        ticketStats.Open,
				"in_progress": ticketStats.InProgress,
				"resolved":    ticketStats.Resolved,
				"closed":      ticketStats.Closed,
			},
			"byPriority": calculateTicketsByPriority(ticketsResp.Tickets),
			"byType":     calculateTicketsByType(ticketsResp.Tickets),
			"trend":      ticketTrend,
			"avgResolutionTime": avgResolutionTime,
			"slaCompliance":     slaCompliance,
		},
		"system": gin.H{
			"uptime":            99.9, // Placeholder
			"totalIncidents":    alertStats["total"],
			"resolvedIncidents": alertStats["resolved"],
			"avgResponseTime":   300, // Placeholder: 5 minutes
		},
	})
}

// GetAlertTrend handles GET /api/analytics/alerts/trend
func (h *AnalyticsHandler) GetAlertTrend(c *gin.Context) {
	ctx := c.Request.Context()
	groupBy := c.DefaultQuery("groupBy", "day")

	alertsResp, err := h.alertClient.ListAlerts(ctx, &alertv1.ListAlertsRequest{
		Pagination: &commonv1.Pagination{
			Page:     1,
			PageSize: 1000,
		},
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	trend := calculateAlertTrendByGroup(alertsResp.Alerts, groupBy)
	c.JSON(http.StatusOK, gin.H{"data": trend})
}

// GetTicketTrend handles GET /api/analytics/tickets/trend
func (h *AnalyticsHandler) GetTicketTrend(c *gin.Context) {
	ctx := c.Request.Context()
	groupBy := c.DefaultQuery("groupBy", "day")

	ticketsResp, err := h.ticketClient.ListTickets(ctx, &ticketv1.ListTicketsRequest{
		Pagination: &commonv1.Pagination{
			Page:     1,
			PageSize: 1000,
		},
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	trend := calculateTicketTrendByGroup(ticketsResp.Tickets, groupBy)
	c.JSON(http.StatusOK, gin.H{"data": trend})
}

// GetPerformanceMetrics handles GET /api/analytics/performance
func (h *AnalyticsHandler) GetPerformanceMetrics(c *gin.Context) {
	ctx := c.Request.Context()

	alertsResp, _ := h.alertClient.ListAlerts(ctx, &alertv1.ListAlertsRequest{
		Pagination: &commonv1.Pagination{Page: 1, PageSize: 1000},
	})
	alertStats := calculateAlertStatistics(alertsResp.Alerts)

	ticketStats, _ := h.ticketClient.GetTicketStatistics(ctx, &ticketv1.GetTicketStatisticsRequest{})

	c.JSON(http.StatusOK, gin.H{
		"alertResponseTime":    180,  // 3 minutes average (placeholder)
		"ticketResolutionTime": 7200, // 2 hours average (placeholder)
		"systemAvailability":   99.9,
		"activeAlerts":         alertStats["firing"],
		"activeTickets":        ticketStats.Open + ticketStats.InProgress,
	})
}

// Helper functions
func calculateAlertStatistics(alerts []*alertv1.Alert) map[string]int {
	stats := map[string]int{
		"total":    len(alerts),
		"firing":   0,
		"resolved": 0,
		"critical": 0,
		"warning":  0,
		"info":     0,
	}

	for _, alert := range alerts {
		if alert.Status == "firing" {
			stats["firing"]++
		} else if alert.Status == "resolved" {
			stats["resolved"]++
		}

		if alert.Severity == "critical" {
			stats["critical"]++
		} else if alert.Severity == "warning" {
			stats["warning"]++
		} else if alert.Severity == "info" {
			stats["info"]++
		}
	}

	return stats
}

func calculateAlertTrend(alerts []*alertv1.Alert) []map[string]interface{} {
	trend := make([]map[string]interface{}, 0)
	countsByDate := make(map[string]int)

	for _, alert := range alerts {
		if alert.StartsAtUnix > 0 {
			date := time.Unix(alert.StartsAtUnix, 0).Format("2006-01-02")
			countsByDate[date]++
		}
	}

	for date, count := range countsByDate {
		trend = append(trend, map[string]interface{}{
			"date":  date,
			"count": count,
		})
	}

	return trend
}

func calculateTicketTrend(tickets []*ticketv1.Ticket) []map[string]interface{} {
	trend := make([]map[string]interface{}, 0)
	countsByDate := make(map[string]int)

	for _, ticket := range tickets {
		if ticket.CreatedAtUnix > 0 {
			date := time.Unix(ticket.CreatedAtUnix, 0).Format("2006-01-02")
			countsByDate[date]++
		}
	}

	for date, count := range countsByDate {
		trend = append(trend, map[string]interface{}{
			"date":  date,
			"count": count,
		})
	}

	return trend
}

func calculateAlertTrendByGroup(alerts []*alertv1.Alert, groupBy string) []map[string]interface{} {
	trend := make([]map[string]interface{}, 0)
	countsByPeriod := make(map[string]int)

	for _, alert := range alerts {
		if alert.StartsAtUnix > 0 {
			t := time.Unix(alert.StartsAtUnix, 0)
			var key string

			switch groupBy {
			case "week":
				// Get ISO week number
				year, week := t.ISOWeek()
				key = fmt.Sprintf("%d-W%02d", year, week)
			case "month":
				key = t.Format("2006-01")
			default: // day
				key = t.Format("2006-01-02")
			}

			countsByPeriod[key]++
		}
	}

	for period, count := range countsByPeriod {
		trend = append(trend, map[string]interface{}{
			"date":  period,
			"count": count,
		})
	}

	return trend
}

func calculateTicketTrendByGroup(tickets []*ticketv1.Ticket, groupBy string) []map[string]interface{} {
	trend := make([]map[string]interface{}, 0)
	countsByPeriod := make(map[string]int)

	for _, ticket := range tickets {
		if ticket.CreatedAtUnix > 0 {
			t := time.Unix(ticket.CreatedAtUnix, 0)
			var key string

			switch groupBy {
			case "week":
				year, week := t.ISOWeek()
				key = fmt.Sprintf("%d-W%02d", year, week)
			case "month":
				key = t.Format("2006-01")
			default: // day
				key = t.Format("2006-01-02")
			}

			countsByPeriod[key]++
		}
	}

	for period, count := range countsByPeriod {
		trend = append(trend, map[string]interface{}{
			"date":  period,
			"count": count,
		})
	}

	return trend
}

func calculateTicketsByPriority(tickets []*ticketv1.Ticket) map[string]int {
	result := map[string]int{
		"critical": 0,
		"high":     0,
		"medium":   0,
		"low":      0,
	}

	for _, ticket := range tickets {
		if count, ok := result[ticket.Priority]; ok {
			result[ticket.Priority] = count + 1
		}
	}

	return result
}

func calculateTicketsByType(tickets []*ticketv1.Ticket) map[string]int {
	result := map[string]int{
		"alert":   0,
		"request": 0,
	}

	for _, ticket := range tickets {
		if ticket.Type != "" {
			result[ticket.Type]++
		}
	}

	return result
}

func calculateAvgResolutionTime(tickets []*ticketv1.Ticket) int {
	var totalTime int64
	var resolvedCount int64

	for _, ticket := range tickets {
		if ticket.Status == "resolved" || ticket.Status == "closed" {
			resolutionTime := ticket.UpdatedAtUnix - ticket.CreatedAtUnix
			totalTime += resolutionTime
			resolvedCount++
		}
	}

	if resolvedCount == 0 {
		return 0
	}

	return int(totalTime / resolvedCount)
}

func calculateSLACompliance(tickets []*ticketv1.Ticket) float64 {
	// Placeholder: assume 95% compliance
	return 95.0
}

func calculateMTTR(alerts []*alertv1.Alert) int {
	var totalTime int64
	var resolvedCount int64

	for _, alert := range alerts {
		if alert.Status == "resolved" && alert.EndsAtUnix > 0 {
			resolutionTime := alert.EndsAtUnix - alert.StartsAtUnix
			totalTime += resolutionTime
			resolvedCount++
		}
	}

	if resolvedCount == 0 {
		return 0
	}

	return int(totalTime / resolvedCount)
}
